home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 001 / ymodem.arc / VVSB.C < prev   
Text File  |  1986-05-27  |  11KB  |  593 lines

  1.  
  2. #define VERSION "vvsb 1.03 01-26-86"
  3.  
  4. /*
  5.  *
  6.  * A small program for VMS which can send 1 or more
  7.  * files with YMODEM protocol to computers running YAM or compatible programs.
  8.  * (Use the "rb" command in YAM.)
  9.  * Supports the CRC option or regular checksum.
  10.  *
  11.  * accepts -k option for 1kb record length.
  12.  *
  13.  * Can send one file with XOMDEM protocol: use "sb -X file"
  14.  *
  15.  * Typical compile and install sequence:
  16.  *        cc vvsb.c
  17.  *        cc vvmodem.c
  18.  *        link vvsb,vvmodem
  19.  *    sb :== $disk$user2:[username.subdir]vvsb.exe
  20.  *
  21.  *    Manual page is "sb.1" in the Unix version rbsb.sh file
  22.  */
  23.  
  24. #define LOGFILE "sblog"
  25.  
  26. #include stdio.h
  27. #include ctype.h
  28. #include "vmodem.h"
  29.  
  30. #ifdef vms
  31. #include ssdef
  32. #include tt2def
  33. #include ttdef
  34. #define SS_NORMAL SS$_NORMAL
  35. #else
  36. #define SS_NORMAL 0
  37. #endif
  38.  
  39. /*  VMS structures  */
  40. #ifdef vms
  41. /*
  42.  *    TT_INFO structures are used for passing information about
  43.  *    the terminal.  Used in GTTY and STTY calls.
  44.  */
  45. struct    tt_info    ttys, ttysnew, ttystemp;
  46. #endif
  47.  
  48.  
  49. #define OK 0
  50. #define FALSE 0
  51. #define TRUE 1
  52. #define ERROR (-1)
  53.  
  54. FILE *in;
  55.  
  56. /* Ward Christensen / CP/M parameters - Don't change these! */
  57. #define ENQ 005
  58. #define CAN ('X'&037)
  59. #define XOFF ('s'&037)
  60. #define XON ('q'&037)
  61. #define SOH 1
  62. #define STX 2
  63. #define EOT 4
  64. #define ACK 6
  65. #define NAK 025
  66. #define CPMEOF 032
  67. #define WANTCRC 0103    /* send C not NAK to get crc not checksum */
  68. #define TIMEOUT (-2)
  69. #define RETRYMAX 10
  70. #define SECSIZ 128    /* cp/m's Magic Number record size */
  71. #define KSIZE 1024
  72.  
  73. char Lastrx;
  74. char Crcflg;
  75. int Verbose=0;
  76. int Quiet=0;        /* overrides logic that would otherwise set verbose */
  77. int Modem=0;        /* MODEM - don't send pathnames */
  78. int Fullname=0;        /* transmit full pathname */
  79. int firstsec;
  80. int errcnt=0;        /* number of files unreadable */
  81. int blklen=SECSIZ;    /* length of transmitted records */
  82. int Totsecs;        /* total number of sectors this file */
  83. char txbuf[KSIZE];
  84. int Filcnt=0;        /* count of number of files opened */
  85.  
  86. unsigned updcrc();
  87. char *substr(), *getenv();
  88.  
  89.  
  90.  
  91. main(argc, argv)
  92. char *argv[];
  93. {
  94.     register char *cp;
  95.     register npats;
  96.     int agcnt; char **agcv;
  97.     char **patts;
  98.     int exitcode;
  99. #ifndef REGULUS
  100.     static char xXbuf[BUFSIZ];
  101. #endif
  102.  
  103.     npats=0;
  104.     if (argc<2)
  105.         goto usage;
  106. #ifndef REGULUS
  107.     setbuf(stdout, xXbuf);        
  108. #endif
  109.     while (--argc) {
  110.         cp = *++argv;
  111.         if (*cp == '-') {
  112.             while ( *++cp) {
  113.                 switch(*cp) {
  114.                 case 'f':
  115.                     Fullname=TRUE; break;
  116.                 case 'k':
  117.                     blklen=KSIZE; break;
  118.                 case 'q':
  119.                     Quiet=TRUE; Verbose=0; break;
  120.                 case 'v':
  121.                     ++Verbose; break;
  122.                 case 'x':
  123.                 case 'X':
  124.                     ++Modem; break;
  125.                 default:
  126.                     goto usage;
  127.                 }
  128.             }
  129.         }
  130.         else if ( !npats && argc>0) {
  131.             if (argv[0][0]) {
  132.                 npats=argc;
  133.                 patts=argv;
  134.             }
  135.         }
  136.     }
  137.     if (npats < 1) {
  138. usage:
  139.         fprintf(stderr,"%s by Chuck Forsberg\n", VERSION);
  140.         fprintf(stderr,"Usage: sb [-fkqv] file ... (YMODEM)\n");
  141.         fprintf(stderr,"or     sb -X [-kqv] file   (XMODEM)\n");
  142.         exit(SS_NORMAL);
  143.     }
  144.     
  145.     if (Verbose) {
  146.         if (freopen(LOGFILE, "a", stderr)==NULL) {
  147.             printf("Can't open log file %s\n",LOGFILE);
  148.             exit(SS_NORMAL);
  149.         }
  150.         setbuf(stderr, NULL);
  151.     }
  152.     if (Verbose != 1) {
  153.         fprintf(stderr, "sb: %d file%s requested:\r\n",
  154.          npats, npats>1?"s":"");
  155.         for ( agcnt=npats, agcv=patts; --agcnt>=0; ) {
  156.             fprintf(stderr, "%s ", *agcv++);
  157.         }
  158.     }
  159.     if ( !Modem)
  160.         printf("\r\n\bSending in Batch Mode\r\n");
  161.     fflush(stdout);
  162.  
  163.     setmodes();
  164.  
  165.     if (wcsend(npats, patts)==ERROR) {
  166.         exitcode=0200;
  167.         canit();
  168.     }
  169.     fflush(stdout);
  170.     restoremodes(FALSE);
  171.     exit(SS_NORMAL);
  172. }
  173.  
  174. wcsend(argc, argp)
  175. char *argp[];
  176. {
  177.     register n;
  178.  
  179.     Crcflg=FALSE;
  180.     firstsec=TRUE;
  181.     for (n=0; n<argc; ++n) {
  182.         Totsecs = 0;
  183.         if (wcs(argp[n])==ERROR)
  184.             goto fubar;
  185.     }
  186.     Totsecs = 0;
  187.     if (Filcnt==0) {    /* bitch if we couldn't open ANY files */
  188.         fprintf(stderr,"\r\nCan't open any requested files.\n");
  189.         return ERROR;
  190.     }
  191.     else if (wctxpn("")==ERROR)
  192.         goto fubar;
  193.     return OK;
  194. fubar:
  195.     canit(); return ERROR;
  196. }
  197.  
  198. wcs(name)
  199. char *name;
  200. {
  201.     register c;
  202.  
  203.     if ((in=fopen(name, "r"))==NULL) {
  204.         ++errcnt;
  205.         return OK;    /* pass over it, there may be others */
  206.     }
  207.     ++Filcnt;
  208.     if (wctxpn(name)!= ERROR)
  209.         return wctx();
  210.     else {
  211.         return ERROR;
  212.     }
  213. }
  214.  
  215. /*
  216.  * generate and transmit pathname block consisting of
  217.  *  pathname (null terminated),
  218.  *  file length provided by RMS
  219.  */
  220. wctxpn(name)
  221. char *name;
  222. {
  223.     register firstch;
  224.     register char *p, *q;
  225.     long filestat();
  226.  
  227.     uncaps(name);        /* Get it out of VMS RADIX50 */
  228.  
  229.     if (Modem)
  230.         return OK;
  231.     logent("\r\nAwaiting pathname nak for %s\r\n", *name?name:"<END>");
  232.     if ((firstch=readline(800))==TIMEOUT) {
  233.         logent("Timeout on pathname\n");
  234.         return ERROR;
  235.     }
  236.     if (firstch==WANTCRC)
  237.         Crcflg=TRUE;
  238.     for (p=name, q=txbuf ; *p; )
  239.         if ((*q++ = *p++) == '/' && !Fullname)
  240.             q = txbuf;
  241.     *q++ = 0;
  242.     p=q;
  243.     while (q < (txbuf + KSIZE))
  244.         *q++ = 0;
  245.  
  246.     if (*name)
  247.         sprintf(p, "%lu", filestat(name));
  248.  
  249.     /* force 1k blocks if name won't fit in 128 byte block */
  250.     if (strlen(txbuf) > 127)
  251.         blklen=KSIZE;
  252.     if (wcputsec(txbuf, 0, SECSIZ)==ERROR)
  253.         return ERROR;
  254.     return OK;
  255. }
  256.  
  257. wctx()
  258. {
  259.     register int sectnum, attempts, firstch;
  260.  
  261.     firstsec=TRUE;
  262.  
  263.     while ((firstch=readline(400))!=NAK && firstch != WANTCRC
  264.       && firstch!=TIMEOUT && firstch!=CAN)
  265.         ;
  266.     if (firstch==CAN) {
  267.         logent("Receiver CANcelled\n");
  268.         return ERROR;
  269.     }
  270.     if (firstch==WANTCRC)
  271.         Crcflg=TRUE;
  272.     sectnum=1;
  273.     while (filbuf(txbuf, blklen)) {
  274.         if (wcputsec(txbuf, sectnum, blklen)==ERROR) {
  275.             return ERROR;
  276.         } else
  277.             sectnum++;
  278.     }
  279.     if (Verbose>1)
  280.         fprintf(stderr, " Closing ");
  281.     fclose(in);
  282.     attempts=0;
  283.     do {
  284.         logent(" EOT ");
  285.         readline(1);
  286.         sendline(EOT);
  287.         fflush(stdout);
  288.         ++attempts;
  289.     }
  290.         while ((firstch=(readline(100)) != ACK) && attempts < RETRYMAX);
  291.     if (attempts == RETRYMAX) {
  292.         logent("No ACK on EOT\n");
  293.         return ERROR;
  294.     }
  295.     else
  296.         return OK;
  297. }
  298.  
  299. wcputsec(buf, sectnum, cseclen)
  300. char *buf;
  301. int sectnum;
  302. int cseclen;    /* data length of this sector to send */
  303. {
  304.     register checksum, wcj;
  305.     register char *cp;
  306.     unsigned oldcrc;
  307.     int firstch;
  308.     int attempts;
  309.  
  310.     firstch=0;    /* part of logic to detect CAN CAN */
  311.  
  312.     if (Verbose>1)
  313.         fprintf(stderr, "\rSector %3d %2dk ", Totsecs, Totsecs/8 );
  314.     for (attempts=0; attempts <= RETRYMAX; attempts++) {
  315.         Lastrx= firstch;
  316.         sendline(cseclen==KSIZE?STX:SOH);
  317.         sendline(sectnum);
  318.         sendline(-sectnum -1);
  319.         oldcrc=checksum=0;
  320.         for (cp=txbuf, wcj=cseclen; wcj; wcj -= 128) {
  321.             raw_wbuf(128, cp);
  322.             cp += 128;
  323.         }
  324.         for (cp=txbuf, wcj=cseclen; --wcj>=0; ) {
  325.             oldcrc=updcrc(*cp, oldcrc);
  326.             checksum += (*cp++);
  327.         }
  328.         if (Crcflg) {
  329.             oldcrc=updcrc(0,updcrc(0,oldcrc));
  330.             sendline((int)oldcrc>>8);
  331.             sendline((int)oldcrc);
  332.         }
  333.         else
  334.             sendline(checksum);
  335.  
  336.  
  337.         firstch = readline(400);
  338. gotnak:
  339.         switch (firstch) {
  340.         case CAN:
  341.             if(Lastrx == CAN) {
  342. cancan:
  343.                 logent("Cancelled\n");  return ERROR;
  344.             }
  345.             break;
  346.         case TIMEOUT:
  347.             logent("Timeout on sector ACK\n"); continue;
  348.         case WANTCRC:
  349.             if (firstsec)
  350.                 Crcflg = TRUE;
  351.         case NAK:
  352.             logent("NAK on sector\n"); continue;
  353.         case ACK: 
  354.             firstsec=FALSE;
  355.             Totsecs += (cseclen>>7);
  356.             return OK;
  357.         default:
  358.             logent("Got %02x for sector ACK\n", firstch);
  359.             break;
  360.         }
  361.         for (;;) {
  362.             Lastrx = firstch;
  363.             if ((firstch = readline(400)) == TIMEOUT)
  364.                 break;
  365.             if (firstch == NAK || firstch == WANTCRC)
  366.                 goto gotnak;
  367.             if (firstch == CAN && Lastrx == CAN)
  368.                 goto cancan;
  369.         }
  370.     }
  371.     if (Verbose)
  372.         logent("Retry Count Exceeded\n");
  373.     return ERROR;
  374. }
  375.  
  376.  
  377. /* fill buf with count chars padding with ^Z for CPM */
  378. filbuf(buf, count)
  379. register char *buf;
  380. {
  381.     register c, m;
  382.     m=count;
  383.     while ((c=getc(in))!=EOF) {
  384.         *buf++ =c;
  385.         if (--m == 0)
  386.             break;
  387.     }
  388.     if (m==count)
  389.         return 0;
  390.     else
  391.         while (--m>=0)
  392.             *buf++ = CPMEOF;
  393.     return count;
  394. }
  395.  
  396.  
  397.  
  398.  
  399.  
  400. /* update CRC */
  401. unsigned updcrc(c, crc)
  402. register c;
  403. register unsigned crc;
  404. {
  405.     register count;
  406.  
  407.     for (count=8; --count>=0;) {
  408.         if (crc & 0x8000) {
  409.             crc <<= 1;
  410.             crc += (((c<<=1) & 0400)  !=  0);
  411.             crc ^= 0x1021;
  412.         }
  413.         else {
  414.             crc <<= 1;
  415.             crc += (((c<<=1) & 0400)  !=  0);
  416.         }
  417.     }
  418.     return crc;    
  419. }
  420.  
  421. /* send 10 CAN's to try to get the other end to shut up */
  422. canit()
  423. {
  424.     register n;
  425.     for (n=10; --n>=0; )
  426.         sendline(CAN);
  427. }
  428.  
  429. #ifdef REGULUS
  430. /*
  431.  * copies count bytes from s to d
  432.  * (No structure assignment in Regulus C compiler)
  433.  */
  434. movmem(s, d, count)
  435. register char *s, *d;
  436. register count;
  437. {
  438.     while (--count >= 0)
  439.         *d++ = *s++;
  440. }
  441. #endif
  442.  
  443. /*VARARGS1*/
  444. logent(a, b, c)
  445. char *a, *b, *c;
  446. {
  447.     if(Verbose)
  448.         fprintf(stderr, a, b, c);
  449. }
  450.  
  451.  
  452. /*
  453.  * substr(string, token) searches for token in string s
  454.  * returns pointer to token within string if found, NULL otherwise
  455.  */
  456. char *
  457. substr(s, t)
  458. register char *s,*t;
  459. {
  460.     register char *ss,*tt;
  461.     /* search for first char of token */
  462.     for (ss=s; *s; s++)
  463.         if (*s == *t)
  464.             /* compare token with substring */
  465.             for (ss=s,tt=t; ;) {
  466.                 if (*tt == 0)
  467.                     return s;
  468.                 if (*ss++ != *tt++)
  469.                     break;
  470.             }
  471.     return NULL;
  472. }
  473.  
  474.  
  475. /* set tty modes for sb transfers */
  476. setmodes()
  477. {
  478. /*  Device characteristics for VMS  */
  479. #ifdef vms
  480.     int    *iptr, parameters;
  481.  
  482. /*
  483.  *    Get current terminal parameters.
  484.  */
  485.     if (gtty(&ttys) != SS$_NORMAL)
  486.         error("SETMODES:  error return from GTTY (1)", FALSE);
  487.     if (gtty(&ttysnew) != SS$_NORMAL)
  488.         error("SETMODES:  error return from GTTY (2)", FALSE);
  489.  
  490. /*
  491.  *    Set new terminal parameters.
  492.  *    Note that there are three bytes of terminal characteristics,
  493.  *    so we should make sure the fourth byte of the integer is unchanged.
  494.  */
  495.     iptr    = &(ttysnew.dev_characteristics.bcharacteristics);
  496.     parameters    = *iptr;
  497.  
  498.     parameters    &= ~TT$M_ESCAPE;        /*  ESCAPE   OFF  */
  499.     parameters    &= ~TT$M_HOSTSYNC;        /*  HOSTSYNC OFF  */
  500.     parameters    |=  TT$M_NOECHO;        /*  NOECHO   ON   */
  501.     parameters    |=  TT$M_PASSALL;        /*  PASSALL  ON   */
  502.     parameters    &= ~TT$M_READSYNC;        /*  READSYNC OFF  */
  503.     parameters    &= ~TT$M_TTSYNC;        /*  TTSYNC   OFF  */
  504.     parameters    &= ~TT$M_WRAP;            /*  WRAP     OFF  */
  505.     parameters    |= TT$M_EIGHTBIT;        /*  EIGHTBIT ON   */
  506.  
  507.     *iptr        = parameters;
  508.  
  509.     if (stty(&ttysnew) != SS_NORMAL)
  510.         error("SETMODES:  error return from STTY", TRUE);
  511. #endif
  512. }
  513.  
  514.  
  515.  
  516. /* restore normal tty modes */
  517. restoremodes(errcall)
  518. int errcall;
  519. {
  520. /*  Device characteristic restoration for VMS  */
  521. #ifdef vms
  522.     if (stty(&ttys) != SS_NORMAL)        /*  Restore original modes  */
  523.         {
  524.         if (!errcall)
  525.             error("Error restoring original terminal params.",
  526.                                     FALSE);
  527.         else
  528.             {
  529.             printf("sb/RESTOREMODES:  ");
  530.             printf("Error restoring original terminal params.\n");
  531.             }
  532.         }
  533. #endif
  534. }
  535.  
  536. /* get a byte from data stream -- timeout if "dseconds" elapses */
  537. /*    NOTE, however, that this function returns an INT, not a BYTE!!!  */
  538. readline(dseconds)
  539. {
  540.     int seconds;
  541.     int    c;
  542.  
  543.     seconds = dseconds/10;
  544.     if (seconds < 5)
  545.         seconds = 5;
  546. #ifdef vms
  547.     c    = raw_read(1, &c, seconds);
  548.  
  549.     if (c == SS$_TIMEOUT)
  550.         return(TIMEOUT);
  551.  
  552.     return(c & 0377);  /* return the char */
  553. #endif
  554. }
  555.  
  556. /* send a byte to data stream */
  557. sendline(data)
  558. {
  559.     char    dataout;
  560.  
  561.     dataout    = data;
  562. #ifdef vms
  563.     raw_write(dataout);
  564. #endif
  565.  
  566. }
  567.  
  568.  
  569. /* print error message and exit; if mode == TRUE, restore normal tty modes */
  570. error(msg, mode)
  571. char *msg;
  572. int mode;
  573. {
  574.     if (mode)
  575.         restoremodes(TRUE);  /* put back normal tty modes */
  576.     printf("sb:  %s\n", msg);
  577.     logent("Fatal Error:  %s\n", msg);
  578.     exit(SS_NORMAL);
  579. }
  580.  
  581.  
  582. /* make string s lower case */
  583. uncaps(s)
  584. register char *s;
  585. {
  586.     for ( ; *s; ++s)
  587.         if ( ! (*s & 0200))
  588.             *s = tolower(*s);
  589. }
  590.  
  591.  
  592.  
  593.